package com.example.run_game;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.*;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.location.Location;
import android.util.Log;
public class DbManager extends SQLiteOpenHelper{
	private ArrayList<Checkpoint> allCheckpoints;
    private static String DB_PATH = "/data/data/com.example.run_game/databases/";
    private static String DB_NAME = "rgdb";
    private SQLiteDatabase db;
    private Context cont;
    private String dbLoc = DB_PATH + DB_NAME;

    private boolean overrideDBinstall = false; 
    
	public DbManager(Context context) 
	{
		super(context, DB_NAME, null, 1);
		allCheckpoints = new ArrayList<Checkpoint>();
		cont = context;
	    boolean dbExists = checkDb();	    
		if(!dbExists || overrideDBinstall)
		{
			try 
	    	{
				copyDb();
			} 
	    	catch (IOException e)
			{
				Log.d("DB", "Copying Failed");
				e.printStackTrace();
			}	
		}			
		readAllCheckpoints();
	}
	
	private boolean checkDb()
	{
		SQLiteDatabase checkDB = null;
		try
		{
	 		checkDB = SQLiteDatabase.openDatabase(dbLoc, null, SQLiteDatabase.OPEN_READWRITE);	 		
		}
		catch(SQLiteException e)
		{		
	   		Log.d("Db", "Database doesn't exist");	
	   	}
		if(checkDB != null)
		{	
	   		Log.d("Db", "Database already exists");
			checkDB.close();	
		}	 
		return checkDB != null;	    
	}

	private void copyDb() throws IOException 
	{
		Log.d("Db", "Copying over database");
		InputStream dbCopySrc = cont.getAssets().open(DB_NAME);
	    File dbDir = new File(DB_PATH); 
        dbDir.mkdir(); 
		OutputStream dboutStream = new FileOutputStream(dbLoc);
		byte[] buffer = new byte[1024];
		int length;
		while ((length = dbCopySrc.read(buffer))>0)
		{
			dboutStream.write(buffer, 0, length);
		}
		dboutStream.flush();
		dboutStream.close();
		dbCopySrc.close();
	}	
	

	private void readAllCheckpoints()
	{
		db = getReadableDatabase();
		Log.d("DB Readable", ""+db.isOpen());
		try{
			Cursor checkpoints = db.rawQuery("select * from checkpoints;", null);	
			//col0 = lat	
			//col1 = long
			//col2 = id
			//col3 = name
			//col4 = desc
			//col5 = region
			//col6 = radius
			for(int i=0; i<checkpoints.getCount(); i++)
			{
				checkpoints.moveToPosition(i);
				Location loc = new Location("");
				loc.setLatitude(checkpoints.getDouble(0));
				loc.setLongitude(checkpoints.getDouble(1));
				//Log.d("Ckp", ""+checkpoints.getDouble(6) +" "+ checkpoints.getString(4)+" "+ checkpoints.getString(3)+" "+ checkpoints.getDouble(0)+" "+ checkpoints.getDouble(1));
				Checkpoint temp = new Checkpoint(checkpoints.getDouble(6), checkpoints.getString(4), checkpoints.getString(3), loc);
		     	allCheckpoints.add(temp);			
			}
		}
		catch (SQLiteException e)
		{
			Log.d("SQL", "Exception in reading all checkpoints");
		}
		db.close();
	}
	
	public Checkpoint[] getAllCheckpoints()
	{
	    Checkpoint[] tempCpA = new Checkpoint[allCheckpoints.size()];
		return allCheckpoints.toArray(tempCpA);
	}
	
	
	public int getPlayerXP()
	{
		db = getReadableDatabase();
		int xp = -100;
		try
		{
			Cursor playerXp = db.rawQuery("select xp from player;", null);	
			playerXp.moveToFirst();
			xp = playerXp.getInt(0);			
		}
		catch (SQLiteException e)
		{
			Log.d("SQL", "Exception in getPlayerXP");
		}
		db.close();
		return xp;
	}
	
	public int getPlayerLevel()
	{
		db = getReadableDatabase();
		int lvl = -100;
		try
		{
			Cursor playerLvl = db.rawQuery("select level from player;", null);	
			playerLvl.moveToFirst();
			lvl = playerLvl.getInt(0);			
		}
		catch (SQLiteException e)
		{
			Log.d("SQL", "Exception in getPlayerLevel");
		}
		db.close();
		return lvl;
	}
	
	public double getPlayerAvSpeed()
	{
		db = getReadableDatabase();
		double AvSpeed = -100;
		try
		{
			Cursor playerSpeed = db.rawQuery("select avDistance, avTime from player;", null);	
			playerSpeed.moveToFirst();
			double distance = playerSpeed.getDouble(0);
			double time = playerSpeed.getDouble(1);
			AvSpeed = distance/time;
		}
		catch (SQLiteException e)
		{
			Log.d("SQL", "Exception in getPlayerSpeed");
		}
		db.close();
		return AvSpeed;
	}
	
	public void onCreate(SQLiteDatabase db) 
	{
	}
	
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
	{
		//No schema changes needed
	}

	public double getTotalAlt()
	{
		db = getReadableDatabase();
		double value = -100;
		try
		{
			Cursor c = db.rawQuery("select totalAltGained from player;", null);	
			c.moveToFirst();
			value = c.getDouble(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public int getTotalDistance()
	{
		db = getReadableDatabase();
		int value = -100;
		try
		{
			Cursor c = db.rawQuery("select totalDistance from player;", null);	
			c.moveToFirst();
			value = c.getInt(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public int getTotalTime()
	{
		db = getReadableDatabase();
		int value = -100;
		try
		{
			Cursor c = db.rawQuery("select totalTime from player;", null);	
			c.moveToFirst();
			value = c.getInt(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public int getTotalRuns()
	{
		db = getReadableDatabase();
		int value = -100;
		try
		{
			Cursor c = db.rawQuery("select totalRuns from player;", null);	
			c.moveToFirst();
			value = c.getInt(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public String getPlayerName()
	{
		db = getReadableDatabase();
		String value = "";
		try
		{
			Cursor c = db.rawQuery("select name from player;", null);	
			c.moveToFirst();
			value = c.getString(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public double getAvDistance()
	{
		db = getReadableDatabase();
		double value = -100;
		try
		{
			Cursor c = db.rawQuery("select avDistance from player;", null);	
			c.moveToFirst();
			value = c.getDouble(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public long getAvTime()
	{
		db = getReadableDatabase();
		long value = -100;
		try
		{
			Cursor c = db.rawQuery("select avTime from player;", null);	
			c.moveToFirst();
			value = c.getLong(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public double getAvSpeed()
	{
		db = getReadableDatabase();
		double value = -100;
		try
		{
			Cursor c = db.rawQuery("select avSpeed from player;", null);	
			c.moveToFirst();
			value = c.getDouble(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public void savePlayer(double totalAltGained, double totalDistance,
			long totalTime, int totalRuns, String name, int level, int xp,
			double avDistance, double avTime, double avSpeed, double weight, 
			double height, int totalCaloriesBurned, Bitmap picture, double bestSpeed, double furthestRun, long longestRun)
	{
			db = getWritableDatabase();
			
			try
			{
				ContentValues args = new ContentValues();
			    args.put("totalAltGained", ""+totalAltGained);
			    args.put("totalDistance", ""+totalDistance);
			    args.put("totalTime", ""+totalTime);
			    args.put("totalRuns", ""+totalRuns);
			    args.put("name", ""+name);
			    args.put("level", ""+level);
			    args.put("xp", ""+xp);
			    args.put("avDistance", ""+avDistance);
			    args.put("avTime", ""+avTime);
			    args.put("avSpeed", ""+avSpeed);
			    args.put("weight", ""+weight);
			    args.put("height", ""+height);
			    args.put("totalCaloriesBurned", ""+totalCaloriesBurned);
			    
			    if(picture != null)
			    {
			    	ByteArrayOutputStream bos = new ByteArrayOutputStream();
			    	picture.compress(Bitmap.CompressFormat.PNG, 100, bos);
			    	byte[] bArray = bos.toByteArray();			    
			    	args.put("picture", bArray);		
			    	byte[] bArray2 = args.getAsByteArray("picture");
			    }			    
			    db.update("player", args, null, null);
			}
			catch (SQLiteException e)
			{
				Log.d("SQL", "Exception in setPlayerXp");
			}
			db.close();		
	}

	public Bitmap getPicture()
	{
		db = getReadableDatabase();
		Bitmap value = null;
		try
		{			
			byte[] bArray;		
			Cursor c = db.rawQuery("select picture from player;", null);	
			c.moveToFirst();
			bArray = c.getBlob(0);		
		    if(bArray == null)
		    	return null;
		    value = BitmapFactory.decodeByteArray(bArray, 0, bArray.length);
	    }
		catch (SQLiteException e) {	Log.d("SQL", "Exception in retrievePicture"); }
		db.close();
		return value;
	}

	
	public int getTotalCaloriesBurned()
	{
		db = getReadableDatabase();
		int value = -100;
		try
		{
			Cursor c = db.rawQuery("select totalCaloriesBurned from player;", null);	
			c.moveToFirst();
			value = c.getInt(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public double getWeight()
	{
		db = getReadableDatabase();
		double value = -100;
		try
		{
			Cursor c = db.rawQuery("select weight from player;", null);	
			c.moveToFirst();
			value = c.getDouble(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public double getHeight()
	{
		db = getReadableDatabase();
		double value = -100;
		try
		{
			Cursor c = db.rawQuery("select height from player;", null);	
			c.moveToFirst();
			value = c.getDouble(0);			
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public double getBestSpeed()
	{
		db = getReadableDatabase();
		double value = -100;
		try
		{
			Cursor c = db.rawQuery("select bestSpeed from player;", null);	
			c.moveToFirst();
			value = c.getDouble(0);	
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public int getFurthestRun()
	{
		db = getReadableDatabase();
		int value = -100;
		try
		{
			Cursor c = db.rawQuery("select furthestRun from player;", null);	
			c.moveToFirst();
			value = c.getInt(0);	
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}

	public int getLongestRun()
	{
		db = getReadableDatabase();
		int value = -100;
		try
		{
			Cursor c = db.rawQuery("select longestRun from player;", null);	
			c.moveToFirst();
			value = c.getInt(0);	
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getPlayerDetails"); }
		db.close();
		return value;
	}
	
	
	public Achievement[] getAchievements()
	{
		db = getReadableDatabase();
		Achievement[] achievements =  new Achievement[10];
		try
		{
			Cursor c = db.rawQuery("select * from achievements;", null);
			int i=0;
			while(c.moveToNext())
			{				
				achievements[i++] = new Achievement(c.getInt(1),c.getString(0) , c.getString(2), cont);	
			}
		}
		catch (SQLiteException e) {	Log.d("SQL", "Exception in getAchievements"); }
		db.close();
		return achievements;
	}
	
	public void saveAchievements(Achievement[] allAch)
	{
		db = getWritableDatabase();		
		try
		{
			for(int i =0; i<allAch.length; i++)
			{
				ContentValues args = new ContentValues();
			    args.put("name", allAch[i].name);
			    args.put("id", ""+allAch[i].id);
			    if(allAch[i].dateUnlocked != "")
			      args.put("dateUnlocked", allAch[i].dateUnlocked);		    
			    db.update("achievements", args, null, null);
			}
		}
		catch (SQLiteException e)
		{
			Log.d("SQL", "Exception in setAchievements");
		}
		db.close();				
	}
	
	
	public void saveSingleAchievement(Achievement ach)
	{
		db = getWritableDatabase();		
		try
		{		ContentValues args = new ContentValues();
			    args.put("name", ach.name);
			    if(!ach.dateUnlocked.equals(""))
			      args.put("dateUnlocked", ach.dateUnlocked);
			    Log.d("DB:", "SAving achievement to DB:" +ach.name + " " + ach.id + " " + ach.dateUnlocked);
			    db.update("achievements", args , "id = "+ ach.id, null);			
		}
		catch (SQLiteException e)
		{
			Log.d("SQL", "Exception in setAchievement");
		}
		db.close();				
	}
	
}

